﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using Ionic.Zip;
using System.Text.RegularExpressions;
using System.ComponentModel;

namespace Reviewer {
    public partial class FrmOnlineReviewRoom : Form {
        private FrmMain frmMain;
        private HGNXHelper helper = new HGNXHelper();
        private string URL_HEADER = "http://www.boardspace.net/hive/hivegames/";
        private string DOWNLOAD_PATH = "";
        string currentFolder = "";
        string parentFolder = "";
        string downloadFile = "";
        string zipFolderName = "";
        WebClient clientLoadList, clientLoadFile, clientLoadZip;
        List<Vector> listFolder, listFile;

        public FrmOnlineReviewRoom(FrmMain frmMain) {
            InitializeComponent();
            this.Icon = Icon.FromHandle(Properties.Resources.world.GetHicon());
            this.frmMain = frmMain;
            DOWNLOAD_PATH = Path.GetTempPath() + "hive.reviewer.cache\\";
        }

        private void FrmOnlineReviewRoom_Load(object sender, EventArgs e) {
            try {
                if(!Directory.Exists(DOWNLOAD_PATH)) {
                    Directory.CreateDirectory(DOWNLOAD_PATH);
                }
                clientLoadFile = new WebClient();
                clientLoadFile.DownloadFileCompleted += new AsyncCompletedEventHandler(clientLoadFile_DownloadFileCompleted);
                clientLoadList = new WebClient();
                clientLoadList.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
                clientLoadZip = new WebClient();
                clientLoadZip.DownloadFileCompleted += new AsyncCompletedEventHandler(clientLoadZip_DownloadFileCompleted);
            } catch(Exception) {
                this.Close();
            }
        }

        private void clientLoadZip_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) {
            if(e.Error != null) {
                tbxStatus.Text = "";
                tbxKeyword.Enabled = true;
                lbxFolders.Enabled = true;
                lbxFiles.Enabled = true;
                return;
            }

            using(ZipFile zipFolder = ZipFile.Read(downloadFile)) {
                if(!Directory.Exists(DOWNLOAD_PATH + zipFolderName)) {
                    Directory.CreateDirectory(DOWNLOAD_PATH + zipFolderName);
                }
                foreach(ZipEntry zip in zipFolder) {
                    zip.Extract(DOWNLOAD_PATH + zipFolderName, ExtractExistingFileAction.OverwriteSilently);
                }
            }
            File.Delete(DOWNLOAD_PATH + zipFolderName + ".zip");
            LoadZipFolder(DOWNLOAD_PATH + zipFolderName);

            tbxStatus.Text = "";
            tbxKeyword.Enabled = true;
            lbxFolders.Enabled = true;
            lbxFiles.Enabled = true;
        }

        private void clientLoadFile_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) {
            if(e.Error != null) {
                tbxStatus.Text = "";
                tbxKeyword.Enabled = true;
                lbxFolders.Enabled = true;
                lbxFiles.Enabled = true;
                return;
            }

            helper.ReadSGFFile(frmMain, downloadFile);

            tbxStatus.Text = "";
            tbxKeyword.Enabled = true;
            lbxFolders.Enabled = true;
            lbxFiles.Enabled = true;
        }

        private void LoadZipFolder(string folder) {
            string keyword = "";
            bool ignorebot = false;

            listFile = new List<Vector>();
            string[] fileNames = Directory.GetFiles(DOWNLOAD_PATH + zipFolderName);
            foreach(string file in fileNames) {
                if(tbxKeyword.Text.Trim() == "") {
                } else {
                    keyword = tbxKeyword.Text.Trim();
                    if(keyword.StartsWith("~")) {
                        ignorebot = true;
                        keyword = keyword.Substring(1);
                    }
                    if(file.Substring(file.LastIndexOf("\\") + 1).IndexOf(keyword, StringComparison.OrdinalIgnoreCase) > -1) {
                        if(ignorebot && file.Substring(file.LastIndexOf("\\") + 1).IndexOf("dumbot", StringComparison.OrdinalIgnoreCase) > -1) {
                            continue;
                        }
                    } else {
                        continue;
                    }
                }
                listFile.Add(new Vector(file.Substring(file.LastIndexOf("\\") + 1), file, "sgff"));
            }
            lbxFiles.DisplayMember = "ID";
            lbxFiles.ValueMember = "Value";
            lbxFiles.DataSource = listFile;
            lbxFiles.SelectedIndex = -1;
        }

        private void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) {
            if(e.Error != null) {
                tbxStatus.Text = "";
                tbxKeyword.Enabled = true;
                lbxFolders.Enabled = true;
                lbxFiles.Enabled = true;
                return;
            }

            listFolder = new List<Vector>();
            listFile = new List<Vector>();

            int countFolder = LoadFolders(e.Result);
            if(countFolder > 0) {
                lbxFolders.DisplayMember = "ID";
                lbxFolders.ValueMember = "Value";
                lbxFolders.DataSource = listFolder;
                lbxFolders.SelectedIndex = -1;
            } else {
                int countZip = LoadZips(e.Result);
                if(countZip > 0) {
                    lbxFolders.DisplayMember = "ID";
                    lbxFolders.ValueMember = "Value";
                    lbxFolders.DataSource = listFolder;
                    lbxFolders.SelectedIndex = -1;
                }
            }

            LoadFiles(e.Result);
            lbxFiles.DisplayMember = "ID";
            lbxFiles.ValueMember = "Value";
            lbxFiles.DataSource = listFile;
            lbxFiles.SelectedIndex = -1;

            tbxStatus.Text = "";
            tbxKeyword.Enabled = true;
            lbxFolders.Enabled = true;
            lbxFiles.Enabled = true;
        }

        private int LoadFolders(string html) {
            MatchCollection mcFolders = Regex.Matches(html, "<img src=\"/icons/folder.gif\" alt=\"\\[DIR\\]\"> <a href=\"(.*)\">");
            if(mcFolders.Count > 0) {
                AddParentFolder(html);
                foreach(Match m in mcFolders) {
                    listFolder.Add(new Vector(m.Groups[1].Value, m.Groups[1].Value, "folder"));
                }
            }
            return listFolder.Count;
        }

        private int LoadZips(string html) {
            MatchCollection mcFolders = Regex.Matches(html, "<img src=\"/icons/compressed.gif\" alt=\"\\[   \\]\"> <a href=\"(.*)\">");
            if(mcFolders.Count > 0) {
                AddParentFolder(html);
                foreach(Match m in mcFolders) {
                    listFolder.Add(new Vector(m.Groups[1].Value, URL_HEADER + currentFolder + m.Groups[1].Value, "zip"));
                }
            }
            return mcFolders.Count;
        }

        private void LoadFiles(string html) {
            string keyword = "";
            bool ignorebot = false;

            MatchCollection mcFiles = Regex.Matches(html, "<img src=\"/icons/unknown.gif\" alt=\"\\[   \\]\"> <a href=\"(.*)\">");
            if(mcFiles.Count > 0) {
                foreach(Match m in mcFiles) {
                    if(tbxKeyword.Text.Trim() == "") {
                    } else {
                        keyword = tbxKeyword.Text.Trim();
                        if(keyword.StartsWith("~")) {
                            ignorebot = true;
                            keyword = keyword.Substring(1);
                        }
                        if(m.Groups[1].Value.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) > -1) {
                            if(ignorebot && m.Groups[1].Value.IndexOf("dumbot", StringComparison.OrdinalIgnoreCase) > -1) {
                                continue;
                            }
                        } else {
                            continue;
                        }
                    }
                    listFile.Add(new Vector(m.Groups[1].Value, URL_HEADER + currentFolder + m.Groups[1].Value, "sgfo"));
                }
            }
        }

        private void DownloadFile(string address, string fileName) {
            try {
                tbxStatus.Text = "Reading...";
                tbxKeyword.Enabled = false;
                lbxFolders.Enabled = false;
                lbxFiles.Enabled = false;
                clientLoadFile.DownloadFileAsync(new Uri(address), fileName);
            } catch(Exception) {
                tbxStatus.Text = "";
                tbxKeyword.Enabled = true;
                lbxFolders.Enabled = true;
                lbxFiles.Enabled = true;
                return;
            }
        }

        private void DownloadZip(string address, string fileName) {
            try {
                tbxStatus.Text = "Reading Zip Directory...";
                tbxKeyword.Enabled = false;
                lbxFolders.Enabled = false;
                lbxFiles.Enabled = false;
                clientLoadZip.DownloadFileAsync(new Uri(address), fileName);
            } catch(Exception) {
                tbxStatus.Text = "";
                tbxKeyword.Enabled = true;
                lbxFolders.Enabled = true;
                lbxFiles.Enabled = true;
                return;
            }
        }

        private void AddParentFolder(string html) {
            Match mParentDirectory = Regex.Match(html, "<img src=\"/icons/back.gif\" alt=\"\\[DIR\\]\"> <a href=\"(.*)\">");
            if(Match.Empty != mParentDirectory && mParentDirectory.Groups[1].Value != "/hive/") {
                parentFolder = mParentDirectory.Groups[1].Value.Replace("/hive/hivegames/", "");
                listFolder.Add(new Vector("../", parentFolder, "folder"));
            } else {
                parentFolder = "/";
                listFolder.Add(new Vector("../", parentFolder, "folder"));
            }
        }

        private void LoadList() {
            try {
                tbxStatus.Text = "Reading Directory...";
                tbxKeyword.Enabled = false;
                lbxFolders.Enabled = false;
                lbxFiles.Enabled = false;
                clientLoadList.DownloadStringAsync(new Uri(URL_HEADER + currentFolder));
            } catch(Exception) {
                tbxStatus.Text = "";
                tbxKeyword.Enabled = true;
                lbxFolders.Enabled = true;
                lbxFiles.Enabled = true;
                return;
            }
        }

        private void FrmOnlineReviewRoom_Shown(object sender, EventArgs e) {
            LoadList();
        }

        private void tbxKeyword_KeyUp(object sender, KeyEventArgs e) {
            if(e.KeyCode == Keys.Enter) {
                FilterGames();
                return;
            }
        }

        private void FilterGames() {
            if(zipFolderName == "") {
                LoadList();
            } else {
                LoadZipFolder(DOWNLOAD_PATH + zipFolderName);
            }
        }

        private void lbxFiles_KeyDown(object sender, KeyEventArgs e) {
            if(e.Control && e.KeyCode == Keys.S) {
                SaveAllGames();
            }
        }

        private void saveAllGamesToolStripMenuItem_Click(object sender, EventArgs e) {
            SaveAllGames();
        }

        private void SaveAllGames() {
            if(listFile.Count == 0) {
                return;
            }
            if((lbxFiles.Items[0] as Vector).Type == "sgfo") {
                return;
            }
            this.Cursor = Cursors.WaitCursor;
            for(int i = 0; i < lbxFiles.Items.Count; i++) {
                helper.ReadSGFFile(frmMain, (lbxFiles.Items[i] as Vector).Value);
                frmMain.SaveGame();
            }
            MessageBox.Show("All games've been saved to local database!", "OK", MessageBoxButtons.OK, MessageBoxIcon.Information);
            this.Cursor = Cursors.Default;
        }

        private void FrmOnlineReviewRoom_FormClosing(object sender, FormClosingEventArgs e) {
            if(clientLoadFile.IsBusy) {
                clientLoadFile.CancelAsync();
            }
            if(clientLoadList.IsBusy) {
                clientLoadList.CancelAsync();
            }
            if(clientLoadZip.IsBusy) {
                clientLoadZip.CancelAsync();
            }
        }

        private void lbxFolders_MouseDoubleClick(object sender, MouseEventArgs e) {
            if(lbxFolders.SelectedIndex < 0) return;
            object obj = lbxFolders.Items[lbxFolders.SelectedIndex];
            if((obj as Vector).Type == "zip") {
                zipFolderName = (obj as Vector).ID.Replace(".zip", "");
                if(Directory.Exists(DOWNLOAD_PATH + zipFolderName)) {
                    LoadZipFolder(DOWNLOAD_PATH + zipFolderName);
                } else {
                    downloadFile = DOWNLOAD_PATH + (obj as Vector).ID;
                    DownloadZip((obj as Vector).Value, DOWNLOAD_PATH + (obj as Vector).ID);
                }
                lbxFiles.ContextMenuStrip = contextMenuStrip1;
                return;
            } else {
                lbxFiles.ContextMenuStrip = null;
                zipFolderName = "";
                currentFolder = (obj as Vector).Value;
                tbxPD.Text = currentFolder;
                LoadList();
            }
        }

        private void lbxFiles_MouseDoubleClick(object sender, MouseEventArgs e) {
            if(lbxFiles.SelectedIndex < 0) return;
            object obj = lbxFiles.Items[lbxFiles.SelectedIndex];
            if((obj as Vector).Type == "sgfo") {
                downloadFile = DOWNLOAD_PATH + (obj as Vector).ID;
                if(!File.Exists(downloadFile)) {
                    DownloadFile((obj as Vector).Value, downloadFile);
                    return;
                } else {
                    helper.ReadSGFFile(frmMain, downloadFile);
                }
            } else {
                helper.ReadSGFFile(frmMain, (obj as Vector).Value);
            }
            tbxStatus.Text = "";
            tbxKeyword.Enabled = true;
            lbxFolders.Enabled = true;
            lbxFiles.Enabled = true;
        }
    }

    class Vector {
        private string _id;
        private string _value;
        private string _type;

        public string ID {
            get { return _id; }
            set { _id = value; }
        }

        public string Value {
            get { return _value; }
            set { _value = value; }
        }

        public string Type {
            get { return this._type; }
            set { this._type = value; }
        }

        public Vector() {
        }

        public Vector(string id, string value, string type) {
            _id = id;
            _value = value;
            _type = type;
        }
    }
}
